package com.hisicom.scqxspxcjc.base.tool;


import cn.hutool.core.util.StrUtil;
import com.hisicom.scqxspxcjc.base.bean.Result;
import com.hisicom.scqxspxcjc.base.enums.ResultEnum;
import io.jsonwebtoken.*;

import javax.servlet.http.HttpServletResponse;
import java.io.InputStream;
import java.security.KeyStore;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.util.Date;
import java.util.Map;

/**
 * @author: zhonggls
 * @date: 2023/3/25 9:06
 * @description: jwt生成token
 */
public class JwtTokenUtil {

    /**
     * 寻找证书文件
     */
    private static InputStream inputStream = Thread.currentThread().getContextClassLoader().getResourceAsStream("jwt.jks");
    private static PrivateKey privateKey = null;
    private static PublicKey publicKey = null;

    static { // 将证书文件里边的私钥公钥拿出来
        try {
            // java key store 固定常量
            KeyStore keyStore = KeyStore.getInstance("JKS");
            keyStore.load(inputStream, "Aqgj,123".toCharArray());
            // jwt 为 命令生成整数文件时的别名
            privateKey = (PrivateKey) keyStore.getKey("jwt", "Aqgj,123".toCharArray());
            publicKey = keyStore.getCertificate("jwt").getPublicKey();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 生成token
     *
     * @param subject           （主体信息）
     * @param expirationSeconds 过期时间（秒）
     * @param claims            自定义身份信息
     * @return
     */
    public static String generateToken(String subject, int expirationSeconds, Map<String, Object> claims) {
        return Jwts.builder()
                .setClaims(claims)
                .setSubject(subject)
                .setExpiration(new Date(System.currentTimeMillis() + expirationSeconds * 1000))
//                .signWith(SignatureAlgorithm.HS512, salt) // 不使用公钥私钥
                .signWith(SignatureAlgorithm.RS256, privateKey)
                .compact();
    }

    /**
     * @author: zhonggls
     * @deprecation: 解析token, 获得subject中的信息
     */
    public static String parseToken(String token, String salt) {
        String subject = null;
        try {
            /*Claims claims = Jwts.parser()
                    .setSigningKey(salt) // 不使用公钥私钥
                    .setSigningKey(publicKey)
                    .parseClaimsJws(token).getBody();*/
            subject = getTokenBody(token).getSubject();
            System.out.println("subject:" + subject);
        } catch (Exception e) {
            e.getMessage();
        }
        return subject;
    }

    /**
     * 获取token自定义属性
     */
    public static Map<String, Object> getClaims(String token) {
        Map<String, Object> claims = null;
        try {
            claims = getTokenBody(token);
        } catch (Exception e) {
            e.getMessage();
        }

        return claims;
    }

    /**
     * 是否已过期
     */
    public static boolean isExpiration(String token) {
        System.out.println(getTokenBody(token).getExpiration());
        return getTokenBody(token).getExpiration().before(new Date());
    }

    public static Claims getTokenBody(String token) {
        return Jwts.parser()
                .setSigningKey(publicKey)
                .parseClaimsJws(token)
                .getBody();
    }

    private static Jws<Claims> parserToken(String token, PublicKey publicKey) {
        return Jwts.parser().setSigningKey(publicKey).parseClaimsJws(token);
    }

    public static Result appVerifyUser(String Authorization, HttpServletResponse response) {
        //验证
        if (StrUtil.isNotBlank(Authorization)) {
            String salt = null;
            try {
                JwtTokenUtil.isExpiration(Authorization);
                salt = JwtTokenUtil.parseToken(Authorization, "_salt");
                if (salt != null && salt != "") {
                    Map<String, Object> claims1 = JwtTokenUtil.getClaims(Authorization);
                    Date expiration = JwtTokenUtil.getTokenBody(Authorization).getExpiration();
                    long nowTime = System.currentTimeMillis();
                    long expirationTime = expiration.getTime();
                    // 结束时间-开始时间 = 分钟
                    long minute = (expirationTime - nowTime) / (60 * 1000);
                    String jwtToken = null;
                    if (minute <= 60) {
                        jwtToken = JwtTokenUtil.generateToken(claims1.get("account") + "", 9000000, claims1);
                    } else {
                        jwtToken = Authorization;
                    }
                    response.setHeader("Authorization", jwtToken);
                    claims1.put("Authorization", jwtToken);
                    return Result.success(claims1);
                } else {
                    return Result.error(ResultEnum.ERROR401);
                }
            } catch (ExpiredJwtException e) {
                if (e.getMessage().contains("Allowed clock skew")) {
                    return Result.error(ResultEnum.ERROR401);
                } else {
                    return Result.error(ResultEnum.ERROR401);
                }
            } catch (Exception e) {
                e.printStackTrace();
                return Result.error(ResultEnum.ERROR401);
            }
        } else {
            return Result.error(ResultEnum.ERROR401);
        }
    }
}